/*
 * Copyright (c) 2024, gaoweixuan (breeze-cloud@foxmail.com).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.breeze.boot.security.sso.client.controller;

import cn.dev33.satoken.util.SaResult;
import com.breeze.boot.core.utils.Result;
import com.breeze.boot.security.sso.client.security.exception.BizException;
import com.breeze.boot.security.sso.client.security.jwt.BreezeJwsTokenProvider;
import com.breeze.boot.security.sso.client.util.SsoRequestUtil;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 前后台分离SSO
 *
 * @author gaoweixuan
 * @since 2024/09/24
 */
@Slf4j
@RestController
@RequiredArgsConstructor
public class SsoWebController {

    private final AuthenticationManager authenticationManager;

    private final BreezeJwsTokenProvider jwsTokenProvider;

    private final RedisTemplate<String, Object> redisTemplate;

    // 当前是否登录
    @RequestMapping("/sso/isLogin")
    public Result<Boolean> isLogin(HttpServletRequest request) {
        Object loginId;
        try {
            String tokenStr = jwsTokenProvider.getTokenStr(request);
            jwsTokenProvider.verifyHMACToken(tokenStr);
            loginId = jwsTokenProvider.getTokenClaim(tokenStr, "LOGIN_ID");
            redisTemplate.opsForValue().get("jwt:blacklist:" + loginId + ":" + tokenStr);
            log.error("当前登录 {}", loginId);
            return Result.ok(Boolean.TRUE);
        } catch (Exception e) {
            return Result.ok(Boolean.FALSE);
        }
    }

    /**
     * 返回SSO认证中心登录地址
     * <p>
     * http://sa-sso-server.com:9000/sso/auth
     * ?client=sso-client1
     * &redirect=http://localhost:3000/#/sso-login?back=http%3A%2F%2Flocalhost%3A3000%2F%23%2Fsso%3Fredirect%3D%2Fhome
     * </p>
     */
    @RequestMapping("/sso/getSsoAuthUrl")
    public Result<String> getSsoAuthUrl(String clientLoginUrl) {
        String serverAuthUrl = SsoRequestUtil.buildServerAuthUrl(clientLoginUrl, "");
        return Result.ok(serverAuthUrl);
    }

    /**
     * 根据ticket进行登录
     *
     * @param ticket  票
     * @param request 请求
     * @return {@link Result }<{@link ? }>
     */
    @RequestMapping("/sso/doLoginByTicket")
    public Result<?> doLoginByTicket(String ticket, HttpServletRequest request) {
        // 获取当前 client 端的单点注销回调地址
        if (SsoRequestUtil.isSlo) {
            String url = request.getRequestURL().toString();
            log.info("当前请求地址: {}", url);
        }

        // 校验 ticket
        String timestamp = String.valueOf(System.currentTimeMillis());    // 时间戳
        String nonce = SsoRequestUtil.getRandomString(20);        // 随机字符串
        String sign = SsoRequestUtil.getCheckTicketSign(ticket, timestamp, nonce);    // 参数签名
        String checkUrl = SsoRequestUtil.checkTicketUrl +
                "?client=sso-client1" +
                "&msgType=checkTicket" +
                "&nonce=" + nonce +
                "&ticket=" + ticket +
                "&timestamp=" + timestamp +
                "&sign=" + sign;

        SaResult result = SsoRequestUtil.request(checkUrl);

        // 使用 satoken 的返回协议 状态200 成功
        if (result.getCode() == 200 && !SsoRequestUtil.isEmpty(result.getData())) {
            // 登录
            Object loginId = result.getData();
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginId, "123456");
            Authentication authentication = authenticationManager.authenticate(authenticationToken);
            return Result.ok(jwsTokenProvider.createJwtToken(authentication));
        }
        throw new BizException(result.getMsg());
    }

}
